/*
 * Renderable.h
 *
 *  Created on: 2009/01/19
 *      Author: Yongshik Cho
 */

#ifndef RENDERABLE_H_
#define RENDERABLE_H_

#include "../core/Vector3D.h"

#include "../core/Matrix4.h"
#include "../core/Color.h"
#include "../core/ISmartPtr.h"


#ifndef EVENTDISPATCHER_H_
#	include "../EventDispatcher.h"
#endif


#ifndef TEXTURE_H_
#	include "../Texture.h"
#endif

#include <vector>
#include <map>
#include "sqplus/sqplus.h"

using namespace SqPlus;


class Rect2D;
class Collidable;
class Audible;
class Tweenable;

class Renderable : public ISmartPtr<Renderable>, public EventDispatcher
{
public:
	enum FLIP_TYPE
	{
		FLIP_NONE = 0,
		FLIP_LEFT_RIGHT,
		FLIP_TOP_BOTTOM
	};

	enum RENDERABLE_TYPE
	{
		RENDERABLE_BITMAP = 0,
		RENDERABLE_CONTAINER,
		RENDERABLE_SHAPE,
		RENDERABLE_PARTICLE,
		RENDERABLE_RIBBON,
		RENDERABLE_TEXT
	};

public:
	friend class RenderObjectContainer;

	Renderable(Renderable* parent = 0, Texture* texture = 0, Vector2D size = Vector2D(0.f, 0.f));
	virtual ~Renderable();

public:
	inline const String& getName() const { return mName; }
	inline void setName(const String& name) { mName = name; }

	inline const Vector2D& getPosition() const { return mPosition; }
	virtual void setPosition(const Vector2D& position);

	inline const float getZ() const { return z; }
	virtual void setZ(const float v) { z = v; }

	inline const Vector2D& getSize() const { return mSize; }
	virtual void setSize(const Vector2D& size);

	inline const Vector2D& getScale() const { return mScale; }
	virtual void setScale(const Vector2D& scale);

	//it is a degree not a radian
	inline const float getRotation() const { return mRotation; }
	virtual void setRotation(const float rotation);

	inline const Vector2D& getOrigin() const { return mOrigin; }
	virtual void setOrigin(const Vector2D& org) { mOrigin = org; }

	inline const Vector2D& getUp() const { return mUp; }
	virtual void setUp(const Vector2D& up) { mUp = up; }

	inline const bool getSort() const { return mSort; }
	virtual void setSort(const bool sort);

	inline const Color& getTransparentColor() const { return mTransparentColor; }
	void setTransparentColor(const Color& color);

	inline const bool getUseTransparentColor() const { return mUseTransparentColor; }
	void setUseTransparentColor(const bool use);

	inline const Color& getBlendColor() const { return mBlendColor; }
	virtual void setBlendColor(const Color& c) { mBlendColor = c; }

	inline const Color& getLineColor() const { return mLineColor; }
	inline void setLineColor(const Color c) { mLineColor = c; }

	inline const bool getVisible() const { return mVisible; }
	virtual void setVisible(const bool visible) { mVisible = visible; }

	inline const bool getLocked() const { return mLocked; }
	virtual void setLocked(const bool locked) { mLocked = locked; }

	inline const bool getVisibleRect() const { return mVisibleRect; }
	inline void setVisibleRect(const bool drawRect) { mVisibleRect = drawRect; }

	inline const bool getVisibleCenter() const { return mVisibleCenter; }
	inline void setVisibleCenter(const bool drawCenter) { mVisibleCenter = drawCenter; }

	inline const bool getVisibleControlPoint() const { return mVisibleControlPoint; }
	inline void setVisibleControlPoint(const bool visibleControlPoint) { mVisibleControlPoint = visibleControlPoint; }

	inline const bool getVisibleAxisAlinedBox() const { return mVisibleAxisAlinedBox; }
	inline void setVisibleAxisAlinedBox(const bool visibleAxisAlinedBox) { mVisibleAxisAlinedBox = visibleAxisAlinedBox; }

	inline const bool getVisibleCollidable() const { return mVisibleCollidable; }
	inline void setVisibleCollidable(const bool visible) { mVisibleCollidable = visible; }

	inline const bool getVisibleCollidablePoint() const { return mVisibleCollidablePoint; }
	inline void setVisibleCollidablePoint(const bool visible) { mVisibleCollidablePoint = visible; }

	inline const bool getVisibleOrigin() const { return mVisibleOrigin; }
	inline void setVisibleOrigin(const bool visible) { mVisibleOrigin = visible; }

	inline const bool getVisibleAttachments() const { return mVisibleAttachments; }
	inline void setVisibleAttachments(const bool visible) { mVisibleAttachments = visible; }

	inline Texture* getTexture() const { return mTexture; }
	virtual void setTexture(Texture* texture);

	const Matrix4 getLocalMatrix();
	const Vector2D getViewScale();

	inline Renderable* getParent() const { return mParent; }
	virtual void setParent(Renderable* parent);

	inline const Matrix4& getMatrix() const { return mMatrix; }

	inline const uint8 getCenterType() const { return mCenterType; }
	virtual void setCenterType(const uint8 type);

	inline const uint8 getFlipType() const { return mFlipType; }
	virtual void setFlipType(const uint8 type) { mFlipType = type; }

	inline const uint8 getCollideType() const { return mCollideType; }
	virtual void setCollideType(const uint8 type) { mCollideType = type; }

	const Vector2D getViewSize();
	virtual const Rect2D& getRect();
	virtual const Rect2D getViewRect();
	virtual const Vector2D getViewPosition(const Vector2D& p);
	virtual const Vector2D getLocalPosition(const Vector2D& p);

	virtual const bool in(const Vector2D& p);

	virtual void preRender();
	virtual void render();
	virtual void postRender();

	virtual const uint32 getChildCount() const { return 0; }

	inline Collidable* getCollidable(const uint32 index)
	{
		if(index >= mCollidables.size())
			return 0;

		return mCollidables[index];
	}
	inline const uint32 getCollidableCount() const { return (uint32)mCollidables.size(); }
	inline void addCollidable(Collidable* collidable)
	{
		if(!collidable)
			return;

		mCollidables.push_back(collidable);
	}

	const Rect2D& getTextureCoords() const;
	const void setTextureCoords(const Rect2D& coords);
	const Rect2D getTextureViewRect();


	void calculateMatrix();
	const bool isPointIn(const Vector2D& p);

	virtual void animate(const String& name) {}
	virtual void animate(const uint32 index) {}
	virtual void animate(const String& name, const uint8 loopType, const uint32 loopCount) {}
	virtual void animate(const uint32 index, const uint8 loopType, const uint32 loopCount) {}
	virtual void tween(const String& name) {}
	virtual void tween(const uint32 index) {}
	virtual void tween(const String& name, const uint8 loopType, const uint32 loopCount) {}
	virtual void tween(const uint32 index, const uint8 loopType, const uint32 loopCount) {}
	virtual void playback(const String& name);
	virtual void playback(const uint32 index);
	virtual void playback(const String& name, uint8 loopType, uint32 loopCount);
	virtual void playback(const uint32 index, uint8 loopType, uint32 loopCount);

	Audible* getAudible(const uint32 index);
	Audible* getAudible(const String& name);

	const uint32 getAudibleCount() const { return (uint32)mAudibles.size(); }
	void addAudible(Audible* audible);

	virtual const uint32 getDepth() const { return mDepth; }
	virtual void setDepth(const uint32 depth) { mDepth = depth; }

	inline void animate_bindable(const String& name) { animate(name); }
	inline void tween_bindable(const String& name) { tween(name); }
	inline void playback_bindable(const String& name) { playback(name); }

	virtual void setTweenable(const String& tween, Tweenable* twn) {}

	inline const uint32 getAttachmentCount() const { return (uint32)mAttachments.size(); }
	const Vector2D getAttachmentByName(const String& name);
	const Vector2D getAttachmentByIndex(const uint32 index);
	virtual void addAttachment(const String& name, const Vector2D& p);

	inline const uint8 getAlpha() const { return (uint8)(mBlendColor.a * 255.f); }
	virtual void setAlpha(uint8 alpha) { mBlendColor.a = (float)alpha/255.f; }

	inline const int32 getBlendType() const { return mBlendType; }
	virtual void setBlendType(const int32 type) { mBlendType = type; }

	inline const uint8 getRenderableType() const { return mRenderableType; }

private:
	void calculatePoints();

protected:
	String		mName;
	Vector2D 	mPosition;
	float		z;
	float		mRotation;	//degree
	Vector2D	mSize;
	Vector2D	mScale;
	Vector2D	mOrigin;
	Vector2D	mUp;
	Rect2D*		mRect;
	Color		mBlendColor;
	Color		mTransparentColor;
	Rect2D*		mTextureCoords;

	Matrix4		mMatrix;

	bool		mVisible;
	bool		mLocked;
	bool		mSort;
	bool		mUseTransparentColor;
	bool		mVisibleRect;
	Color		mLineColor;
	bool		mVisibleCenter;
	bool		mVisibleCollidable;
	bool		mVisibleCollidablePoint;
	bool		mVisibleControlPoint;
	bool		mVisibleAxisAlinedBox;
	bool		mVisibleOrigin;
	bool		mVisibleAttachments;

	Texture*	mTexture;
	Renderable*	mParent;
	uint8		mCenterType;
	uint8		mFlipType;
	uint8		mCollideType;
	int32		mBlendType;
	int8		mRenderableType;

	uint32		mDepth;

	vector<Collidable*> mCollidables;
	vector<Audible*>	mAudibles;
	map<String, Vector2D>	mAttachments;

};

//must be declared here
DECLARE_INSTANCE_TYPE(Renderable)

#endif /* RENDERABLE_H_ */
